Adder

Adder是一种卷积替代算子,它使用L1距离度量(绝对差的和)代替传统卷积中的点积操作。与标准卷积不同,Adder通过计算特征与卷积核之间的绝对差的负和来进行特征提取。假定输入X,filter表示为F,它按以下公式计算:

\[Y(m,n,t) = - \sum_{i=0}^{d} \sum_{j=0}^{d} \sum_{k=0}^{C_{in}} |X(m+i, n+j, k) - F(i,j,k,t)|\]
输入:
  • input_x - 输入数据的地址

  • input_w - 输入卷积核权重的地址

  • bias - 输入偏置的地址

  • param - 算子计算所需参数的结构体。其各成员见下述。

  • core_mask - 核掩码。

AdderParameter定义:

 1typedef struct AdderParameter {
 2    void* workspace_; // 用于存放中间计算结果
 3    int output_batch_; // 输出数据总批次
 4    int input_batch_; // 输入数据总批次
 5    int input_h_; // 输入数据h维度大小
 6    int input_w_; // 输入数据w维度大小
 7    int output_h_; // 输出数据h维度大小
 8    int output_w_; // 输出数据w维度大小
 9    int input_channel_; // 输入数据通道数
10    int output_channel_; // 输出数据通道数
11    int kernel_h_; // 卷积核h维度大小
12    int kernel_w_; // 卷积核w维度大小
13    int group_; // 组数
14    int pad_l_; // 左填充大小
15    int pad_u_; // 上填充大小
16    int dilation_h_; // 卷积核h维度膨胀尺寸大小
17    int dilation_w_; // 卷积核w维度膨胀尺寸大小
18    int stride_h_; // 卷积核h维度步长
19    int stride_w_; // 卷积核w维度步长
20    int buffer_size_; // 为分块计算所分配的缓存大小
21} AdderParameter;
输出:
  • out_y - 输出地址。

支持平台:

FT78NE MT7004

备注

  • FT78NE 支持int8, fp32

  • MT7004 支持fp16, fp32

共享存储版本:

void i8_adder_s(int8_t *input_x, int8_t *input_w, int8_t *out_y, int *bias, AdderParameter *param, int core_mask)
void hp_adder_s(half *input_x, half *input_w, half *out_y, half *bias, AdderParameter *param, int core_mask)
void fp_adder_s(float *input_x, float *input_w, float *out_y, float *bias, AdderParameter *param, int core_mask)

C调用示例:

 1void TestAdderSMCFp32(int* input_shape, int* weight_shape, int* output_shape, int* stride, int* padding, int* dilation, int groups, float* bias, int core_mask) {
 2    int core_id = get_core_id();
 3    int logic_core_id = GetLogicCoreId(core_mask, core_id);
 4    int core_num = GetCoreNum(core_mask);
 5    float* input_data = (float*)0x88000000;
 6    float* weight = (float*)0x89000000;
 7    float* output_data = (float*)0x90000000;
 8    float* bias_data = (float*)0x91000000;
 9    AdderParameter* param = (AdderParameter*)0x92000000;
10    if (logic_core_id == 0) {
11        memcpy(bias_data, bias, sizeof(float) * output_shape[3]);
12        param->dilation_h_ = dilation[0];
13        param->dilation_w_ = dilation[1];
14        param->group_ = groups;
15        param->input_batch_ = input_shape[0];
16        param->input_h_ = input_shape[1];
17        param->input_w_ = input_shape[2];
18        param->input_channel_ = input_shape[3];
19        param->kernel_h_ = weight_shape[1];
20        param->kernel_w_ = weight_shape[2];
21        param->output_batch_ = output_shape[0];
22        param->output_h_ = output_shape[1];
23        param->output_w_ = output_shape[2];
24        param->output_channel_ = output_shape[3];
25        param->stride_h_ = stride[0];
26        param->stride_w_ = stride[0];
27        param->pad_u_ = padding[0];
28        param->pad_l_ = padding[2];
29        param->workspace_ = (float*)0x10000000; // workspace空间需分配在AM内,计算过程中会将数据搬运到workspace空间内进行计算
30    }
31    sys_bar(0, core_num); // 初始化参数完成后进行同步
32    fp_adder_s(input_data, weight, output_data, bias_data, param, core_mask);
33}
34
35void main(){
36    int in_channel = 4;
37    int out_channel = 4;
38    int groups = 4;
39    int input_shape[4] = {1, 30, 30, in_channel}; // NHWC
40    int weight_shape[4] = {out_channel, 3, 3, in_channel / groups};
41    int output_shape[4] = {1, 10, 10, out_channel}; // NHWC
42    int stride[2] = {2, 2};
43    int padding[4] = {1, 1, 1, 1};
44    int dilation[2]= {2, 2};
45    float bias[4] = {0, 0, 0, 0};
46    int core_mask = 0b1111;
47    TestAdderSMCFp32(input_shape, weight_shape, output_shape, stride, padding, dilation, groups, bias, core_mask);
48}

私有存储版本:

void i8_adder_p(int8_t *input_x, int8_t *input_w, int8_t *out_y, int *bias, ConvParameter *conv_param, ConvQuantParameter quant_param, int core_mask)
void hp_adder_p(half *input_x, half *input_w, half *out_y, half *bias, ConvParameter *conv_param, int core_mask)
void fp_adder_p(float *input_x, float *input_w, float *out_y, float *bias, ConvParameter *conv_param, int core_mask)

C调用示例:

 1void TestAdderL2Fp32(int* input_shape, int* weight_shape, int* output_shape, int* stride, int* padding, int* dilation, int groups, float* bias, int core_mask) {
 2    float* input_data = (float*)0x10010000; // 私有存储版本地址设置在AM内
 3    float* weight = (float*)0x10020000;
 4    float* output_data = (float*)0x10030000;
 5    float* bias_data = (float*)0x10040000;
 6    AdderParameter* param = (AdderParameter*)0x10060000;
 7    memcpy(bias_data, bias, sizeof(float) * output_shape[3]);
 8    param->dilation_h_ = dilation[0];
 9    param->dilation_w_ = dilation[1];
10    param->group_ = groups;
11    param->input_batch_ = input_shape[0];
12    param->input_h_ = input_shape[1];
13    param->input_w_ = input_shape[2];
14    param->input_channel_ = input_shape[3];
15    param->kernel_h_ = weight_shape[1];
16    param->kernel_w_ = weight_shape[2];
17    param->output_batch_ = output_shape[0];
18    param->output_h_ = output_shape[1];
19    param->output_w_ = output_shape[2];
20    param->output_channel_ = output_shape[3];
21    param->stride_h_ = stride[0];
22    param->stride_w_ = stride[0];
23    param->pad_u_ = padding[0];
24    param->pad_l_ = padding[2];
25    param->workspace_ = (float*)0x10070000;
26    param->buffer_size_ = 2048; // 私有存储版本中,必须设置该参数,用于确定分块计算的大小
27    fp_adder_p(input_data, weight, output_data, bias_data, param, core_mask);
28}
29
30void main(){
31    int in_channel = 4;
32    int out_channel = 4;
33    int groups = 4;
34    int input_shape[4] = {1, 30, 30, in_channel}; // NHWC
35    int weight_shape[4] = {out_channel, 3, 3, in_channel / groups};
36    int output_shape[4] = {1, 10, 10, out_channel}; // NHWC
37    int stride[2] = {2, 2};
38    int padding[4] = {1, 1, 1, 1};
39    int dilation[2]= {2, 2};
40    float bias[4] = {0, 0, 0, 0};
41    int core_mask = 0b0001; // 私有存储版本只能设置为一个核心启动
42    TestAdderL2Fp32(input_shape, weight_shape, output_shape, stride, padding, dilation, groups, bias, core_mask);
43}